from scrapy import signals, Request
from scrapy.crawler import Crawler
from scrapy.http.response.text import TextResponse
from curl_cffi.requests.errors import CurlError


class CurlDownloaderMiddleware:
    # Not all methods need to be defined. If a method is not defined,
    # scrapy acts as if the downloader middleware does not modify the
    # passed objects.

    @classmethod
    def from_crawler(cls, crawler: Crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_request(self, request: Request, spider):
        """
         Called for each request that goes through the downloader
         middleware.

         Must either:
         - return None: continue processing this request
         - or return a Response object
         - or return a Request object
         - or raise IgnoreRequest: process_exception() methods of
           installed downloader middleware will be called
        """
        if getattr(spider, 'curl_session'):
            spider.logger.warning('curl session')
            request.headers.pop('user-agent', None)
            headers = {k.decode(): v[0].decode() for k, v in request.headers.items()}
            resp = spider.curl_session.request(
                url=request.url,
                method=request.method,
                data=request.body,
                headers=headers,
                cookies=request.cookies
            )
            return TextResponse(
                url=resp.url,
                status=resp.status_code,
                headers=resp.headers,
                body=resp.content,
                request=request,
            )

    def process_response(self, request: Request, response, spider):
        """
        Called with the response returned from the downloader.

        Must either;
        - return a Response object
        - return a Request object
        - or raise IgnoreRequest
        :return:
        """
        return response

    def process_exception(self, request, exception, spider):
        """
        Called when a download handler or a process_request()
        (from other downloader middleware) raises an exception.

        Must either:
        - return None: continue processing this exception
        - return a Response object: stops process_exception() chain
        - return a Request object: stops process_exception() chain
        """

    def spider_opened(self, spider):
        """spider.logger.info("Spider opened: %s" % spider.name)"""
